import { resolve } from "path";
import fs from "node:fs";
import axios from "axios";
import { ElNotification } from "@chulei-ui/element-plus";
import scrapeIt from "scrape-it";
import { BigDecimal } from "@chulei-ui/utils";

import { ArrayUtils, FileUtils } from "../../utils";

import {
  ALL_CHECK_SUM_TEXT,
  ICON_DIR,
  SDE_CHECKSUM_FILE,
  SDE_FILE,
  SDE_FILE_NAME,
  SDE_FILE_TEXT,
  SDE_PAGE_URL,
  SDE_UNPACK_DIR,
} from "../contanst";
import {
  reformatBluePrints,
  reformatCategory,
  reformatPlanetSchematics,
  reformatTypeMaterials,
  reformatTypes,
} from "../formaters";

type SDEFileChecksum = { checksum: string; file: string };

export type LoadingControl = {
  setText(text: string): void;
};

type Link = { link: string; text: string };

export class SDEFileUtils {
  /**
   * 从指定的 URL 下载校验和文件并解析其内容。
   *
   * @param {string} link - 要下载的校验和文件的 URL。
   */
  static async downloadChecksum(link: string) {
    try {
      const file = await axios<string>({
        method: "get",
        url: link,
        responseType: "text",
      });
      return file.data.split("\n").map((item) => {
        const [checksum, file] = item.split("  ");
        return {
          checksum,
          file,
        } as SDEFileChecksum;
      });
    } catch (e: any) {
      ElNotification({
        type: "error",
        title: "SDE校验文件下载失败",
        message: e.message,
      });
      throw new Error(`SDE校验文件下载失败: ${e.message}`);
    }
  }
  /**
   * 通过抓取预定义页面来获取 （SDE） 链接。
   *
   */
  static async fetchSDELinks() {
    const { data } = await scrapeIt<{ links: Link[] }>(SDE_PAGE_URL, {
      links: {
        listItem: "a",
        data: {
          link: {
            attr: "href",
          },
          text: {
            how: "html",
          },
        },
      },
    });
    const checkSumLink = data.links.find((link) => link.text === ALL_CHECK_SUM_TEXT);
    const sdeLink = data.links.find((link) => link.text === SDE_FILE_TEXT);
    return {
      checkSumLink,
      sdeLink,
    };
  }

  static async unpack() {
    await FileUtils.unpack(SDE_FILE, SDE_UNPACK_DIR);
  }

  static async reformat(loading?: LoadingControl) {
    const types = await reformatTypes(loading);
    const typeMap = ArrayUtils.toMap(types, (type) => type.id);
    reformatTypeMaterials(typeMap);
    reformatBluePrints(typeMap);
    reformatPlanetSchematics(typeMap);
    await reformatCategory(loading);
  }

  /**
   * 校验checksum是否已失效
   * @param check
   * @param sde
   * @param loading
   */
  static async download(check: SDEFileChecksum | undefined, sde: Link, loading: LoadingControl | undefined) {
    let fileChecksums;
    try {
      if (!check) return;
      const oldChecksumFile = FileUtils.exist(SDE_CHECKSUM_FILE);
      if (oldChecksumFile) {
        fileChecksums = FileUtils.readJSON<SDEFileChecksum>(SDE_CHECKSUM_FILE);
        const cacheChecksum = fileChecksums.find((sdeChecksum) => sdeChecksum.file === check.file);
        if (cacheChecksum?.checksum === check.checksum) {
          return;
        }
      }
      const response = await axios({
        method: "get",
        url: sde.link,
        responseType: "arraybuffer",
        onDownloadProgress(event) {
          loading?.setText(
            `SDE文件下载 ${BigDecimal.form(event.loaded)!.divide(event.total).multiply(100)!.toFixed(2)?.toNumber()!}%`
          );
        },
      });
      loading?.setText("SDE文件下载完成");
      FileUtils.saveFile(SDE_FILE, Buffer.from(response.data));
      await this.unpack();
      loading?.setText("文件解压缩完成");
      await this.reformat(loading);
      FileUtils.writeJSON(SDE_CHECKSUM_FILE, [check]);
    } catch (error: any) {
      console.error("文件下载或保存失败:", error);
      ElNotification({
        type: "error",
        title: "SDE资源加载出错",
        message: error.message,
      });
    }
  }

  static getSDEFileCheckSum(checksums?: SDEFileChecksum[]) {
    return checksums?.find((file) => file.file === SDE_FILE_NAME);
  }

  static async saveImage(typeId: number) {
    if (!fs.existsSync(ICON_DIR)) {
      fs.mkdirSync(ICON_DIR, { recursive: true });
    }
    const iconPath = resolve(ICON_DIR, `${typeId}.png`);
    if (FileUtils.exist(iconPath)) {
      return false;
    }
    const image = await axios({
      url: `https://image.evepc.163.com/Type/${typeId}_64.png`,
      method: "get",
      responseType: "arraybuffer",
    });
    FileUtils.saveFile(iconPath, Buffer.from(image.data));
    return true;
  }
}
